﻿#pragma once
#include <thread>
#include <atomic>
#include <chrono>
#include <functional>

template<typename T>
struct SmoothValue {
    std::atomic<T> current{ 0 };
    std::atomic<T> target{ 0 };
    std::atomic<bool> running{ false };
    std::thread worker;

    static constexpr auto STEP_MS = std::chrono::milliseconds(128);
    static constexpr int32_t STEPS = 5000 / 128; // 40 步

    void start(std::function<void(T)> on_step = {}) {
        bool expected = false;
        if (!running.compare_exchange_strong(expected, true)) return;

        worker = std::thread([this, on_step]()
            {
                T src = current.load();
                T dst = target.load();
                for (int i = 1; i <= STEPS && running; ++i)
                {
                    T val = src + (dst - src) * i / STEPS;
                    current.store(val);
                    if (on_step) on_step(val);
                    std::this_thread::sleep_for(STEP_MS);
                }
                if (running.load())
                {
                    current.store(dst);
                    if (on_step) on_step(dst);
                }
                running.store(false);
            });
    }

    void stop() {
        running.store(false);
        if (worker.joinable()) worker.join();
    }

    void set_target(T t, std::function<void(T)> on_step = {}) {
        if (current.load() == t) {
            if (on_step) on_step(t);
            return;
        }
        stop();
        target.store(t);
        start(on_step);
    }
};
